﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Input;
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using MusicExplorer.Helper;
using MusicExplorer.Internals;
using MusicExplorer.View.Popup;
using MusicExplorer.ViewModel.Popup;
using MusicExplorer.WebRepository.Interface;
using MusicExplorer.WebRepository.Service;
using MusicExplorer.Wrappers;

namespace MusicExplorer.ViewModel
{
    public sealed class DetailTreeViewModel : ViewModelBase, IDisposable
    {
        private MainWindowViewModel m_parent;
        public MainWindowViewModel Parent { get { return m_parent; } }

        public DetailTreeViewModel(MainWindowViewModel parent)
        {
            m_parent = parent;

            m_webClientLoading = new WebClient();
            m_tokenLoading = new CancellationTokenSource();
        }

        #region GENRES LOADING TASK

        private readonly WebClient m_webClientLoading;
        public WebClient WebClientLoading { get { return m_webClientLoading; } }

        private CancellationTokenSource m_tokenLoading;
        public CancellationTokenSource TokenLoading
        {
            get { return m_tokenLoading; }
            set { m_tokenLoading = value; }
        }

        private Task m_taskLoading;
        public Task TaskLoading
        {
            get { return m_taskLoading; }
            set { m_taskLoading = value; }
        }

        #endregion

        #region FUNCTIONS

        public void RefreshTree()
        {
            if (SelectedWebRepository != null)
            {
                Parent.TrackList.TaskTracksLoading = null;
                Parent.TrackList.Tracks.Clear();
                SelectedGroup = null;
                Parent.Player.Stop();
                Task.Factory.StartNew(() => LoadDetailTree(true));
            }
        }

        void GroupChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
        {
            if (e.PropertyName == "IsSelected")
            {
                SelectedGroup = (DetailTreeItemWrapper)sender;
            }
        }

        void ArtistChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
        {
            if (e.PropertyName == "IsSelected")
            {
                SelectedArtist = (DetailTreeItemWrapper)sender;
            }
        }

        private void LoadDetailTree(bool fromLocalSource)
        {
            var groupRepository = SelectedWebRepository.WebRepository as IGroupFilterWebRepository;
            if (groupRepository != null)
            {
                Parent.Log.SetLog("Loading of " + SelectedWebRepository.DisplayName + "...", LogTypeEnum.Loading);
                SelectedWebRepository.IsLoading = true;

                if (m_tokenLoading.IsCancellationRequested)
                    return;

                Task<List<MusicExplorer.Data.GROUP>> taskGroups;
                if (!fromLocalSource)
                    taskGroups = groupRepository.GetGroupsAsync(m_webClientLoading, TokenLoading.Token);
                else
                    taskGroups = Task.Factory.StartNew(() => ServiceWebRepository.GetGroupsFromWebRepository(SelectedWebRepository.WebRepository.WebRepository));

                try
                {
                    taskGroups.Wait();
                }
                catch (Exception ex)
                {
                    SelectedWebRepository.IsLoading = false;
                    Parent.Log.LogError(ex);
                    return;
                }

                if (m_tokenLoading.IsCancellationRequested)
                    return;

                MusicExplorerHelper.ExecuteInUIThread(() =>
                {
                    SelectedWebRepository.Groups.Clear();
                    foreach (var group in taskGroups.Result.Where(g => g.group_visibility).OrderBy(g => g.group_order))
                    {
                        var g = new DetailTreeItemWrapper(group);
                        g.PropertyChanged += GroupChanged;
                        SelectedWebRepository.Groups.Add(g);
                    }
                });

                SelectedWebRepository.IsLoading = false;

                Parent.Log.ResetLog();
            }

            if (SelectedWebRepository.WebRepository is IArtistFilterWebRepository)
            {
                MusicExplorerHelper.ExecuteInUIThread(() =>
                {
                    SelectedWebRepository.Artists.Clear();
                    foreach (var artist in ServiceWebRepository.GetRegisteredArtistsFromWebRepository(SelectedWebRepository.WebRepository.WebRepository).Where(a => a.artist_visibility).OrderBy(a => a.artist_order))
                    {
                        var a = new DetailTreeItemWrapper(artist);
                        a.PropertyChanged += ArtistChanged;
                        SelectedWebRepository.Artists.Add(a);
                    }
                });
            }
        }

        #endregion

        #region PROPERTIES

        private DetailTreeItemWrapper m_selectedItem;
        public DetailTreeItemWrapper SelectedItem
        {
            get { return m_selectedItem; }
            set
            {
                if (m_selectedItem != value)
                {
                    m_selectedItem = value;
                    RaisePropertyChanged("SelectedItem");
                    Parent.TrackList.Load(m_selectedItem);
                }
            }
        }

        private DetailTreeItemWrapper m_selectedArtist;
        public DetailTreeItemWrapper SelectedArtist
        {
            get { return m_selectedArtist; }
            set
            {
                if (m_selectedArtist != value)
                {
                    m_selectedGroup = null;
                    m_selectedArtist = value;
                    RaisePropertyChanged("SelectedGroup");
                    RaisePropertyChanged("SelectedArtist");
                    if (m_selectedArtist != null) SelectedItem = m_selectedArtist;
                }
            }
        }

        private DetailTreeItemWrapper m_selectedGroup;
        public DetailTreeItemWrapper SelectedGroup
        {
            get { return m_selectedGroup; }
            set
            {
                if (m_selectedGroup != value)
                {
                    m_selectedArtist = null;
                    m_selectedGroup = value;
                    RaisePropertyChanged("SelectedGroup");
                    RaisePropertyChanged("SelectedArtist");
                    if (m_selectedGroup != null) SelectedItem = m_selectedGroup;
                }
            }
        }

        private WebRepositoryWrapper m_selectedWebRepository;
        public WebRepositoryWrapper SelectedWebRepository
        {
            get { return m_selectedWebRepository; }
            set
            {
                if (m_selectedWebRepository != value)
                {
                    if(m_selectedWebRepository != null) m_selectedWebRepository.IsLoading = false;

                    m_selectedWebRepository = value;
                    RaisePropertyChanged("SelectedWebRepository");

                    if (m_selectedWebRepository != null)
                    {
                        StopCurrentTreeLoading();

                        m_taskLoading = Task.Factory.StartNew(() => LoadDetailTree(false));
                    }
                }
            }
        }

        public void StopCurrentTreeLoading()
        {
            Parent.Player.Reset();

            // Si des tracks sont en chargement, on l'arrête avant de changer de repo
            Parent.TrackList.TokenTracksLoading.Cancel();
            Parent.TrackList.WebClientTracksLoading.CancelAsync();
            Parent.TrackList.Tracks.Clear();

            if (Parent.TrackList.TaskTracksLoading != null)
            {
                // This task has cancel pending and stop in few ms
                Parent.TrackList.TaskTracksLoading.Wait();
            }

            SelectedItem = null;
            m_selectedWebRepository.Groups.Clear();
            m_selectedWebRepository.Artists.Clear();

            m_tokenLoading.Cancel();
            m_webClientLoading.CancelAsync();

            if (m_taskLoading != null)
            {
                // This task has cancel pending and stop in few ms
                m_taskLoading.Wait();
            }

            m_tokenLoading = new CancellationTokenSource();
        }

        #endregion

        #region PREFERENCES

        public ICommand OpenGroupPreferences
        {
            get
            {
                return new RelayCommand(() =>
                {
                    var preferences = new EntityPreferences() { DataContext = new GroupPreferencesViewModel(Parent, SelectedWebRepository.WebRepository) };
                    var result = preferences.ShowDialog();
                    if (result.HasValue && result.Value)
                    {
                        var dataContext = preferences.DataContext as GroupPreferencesViewModel;
                        dataContext.UpdateEntities();
                        ServiceWebRepository.SaveGroupPreferences(SelectedWebRepository.WebRepository.WebRepository, dataContext.Entities.Select(w => w.Entity as MusicExplorer.Data.GROUP));
                    }
                    Parent.DetailTree.RefreshTree();
                });
            }
        }

        public ICommand OpenArtistPreferences
        {
            get
            {
                return new RelayCommand(() =>
                {
                    var preferences = new EntityPreferences() { DataContext = new ArtistPreferencesViewModel(Parent, SelectedWebRepository.WebRepository) };
                    var result = preferences.ShowDialog();
                    if (result.HasValue && result.Value)
                    {
                        var dataContext = preferences.DataContext as ArtistPreferencesViewModel;
                        dataContext.UpdateEntities();
                        ServiceWebRepository.SaveArtistPreferences(SelectedWebRepository.WebRepository.WebRepository, dataContext.Entities.Select(w => w.Entity as MusicExplorer.Data.ARTIST));
                    }
                    Parent.DetailTree.RefreshTree();
                });
            }
        }

        #endregion

        public void Dispose()
        {
            if (m_webClientLoading != null) m_webClientLoading.Dispose();
            if (m_tokenLoading != null) m_tokenLoading.Dispose();
        }
    }
}